<!DOCTYPE html>
<html>
  <head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
  <meta name="description" content="tong.li&#39;s blog">
  <meta name="keyword" content="彤哥哥博客，95后技术爱好者,现就职于同程旅行/同程艺龙上海分公司，专注于互联网技术分享的平台。">
  
    <link rel="shortcut icon" href="/css/images/icon.png">
  
  <title>
    
      面试官:你真的了解Java对象吗 | 彤哥哥的博客
    
  </title>
  <link href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <link href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" rel="stylesheet">
  <link href="https://cdn.staticfile.org/highlight.js/9.12.0/styles/tomorrow-night.min.css" rel="stylesheet">
  
<link rel="stylesheet" href="/css/style.css">

  
  <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
  <script src="https://cdn.staticfile.org/geopattern/1.2.3/js/geopattern.min.js"></script>
  <script src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js"></script>
  
    
<script src="/js/qrious.js"></script>

  
  
  
  
    <!-- MathJax support START -->
    <script type="text/x-mathjax-config">
      MathJax.Hub.Config({
        tex2jax: {
          inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
          processEscapes: true,
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
        }
      });
    </script>

    <script type="text/x-mathjax-config">
      MathJax.Hub.Queue(function() {
        var all = MathJax.Hub.getAllJax(), i;
        for (i=0; i < all.length; i += 1) {
          all[i].SourceElement().parentNode.className += ' has-jax';
        }
      });
    </script>
    <script type="text/javascript" src="https://cdn.staticfile.org/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
    <!-- MathJax support END -->
  


  
  
    
<script src="/js/local-search.js"></script>


<meta name="generator" content="Hexo 5.4.2"></head>
<div class="wechat-share">
  <img src="/css/images/logo.png" />
</div>
  <body>
    <header class="header fixed-header">
  <div class="header-container">
    <a class="home-link" href="/">
      <div class="logo"></div>
      <span>彤哥哥的博客</span>
    </a>
    <ul class="right-list">
      
        <li class="list-item">
          
            <a href="/" class="item-link">主页</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/series/" class="item-link">分类</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/tags/" class="item-link">标签</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/archives/" class="item-link">归档</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/project/" class="item-link">项目</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/about/" class="item-link">关于</a>
          
        </li>
      
      
        <li class="menu-item menu-item-search right-list">
    <a role="button" class="popup-trigger">
        <i class="fa fa-search fa-fw"></i>
    </a>
</li>
      
    </ul>
    <div class="menu">
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
    </div>
    <div class="menu-mask">
      <ul class="menu-list">
        
          <li class="menu-item">
            
              <a href="/" class="menu-link">主页</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/series/" class="menu-link">分类</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/tags/" class="menu-link">标签</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/archives/" class="menu-link">归档</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/project/" class="menu-link">项目</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/about/" class="menu-link">关于</a>
            
          </li>
        
      </ul>
    </div>
    
      <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
            <span class="search-icon">
                <i class="fa fa-search"></i>
            </span>
            <div class="search-input-container">
                <input autocomplete="off" autocapitalize="off"
                    placeholder="Please enter your keyword(s) to search." spellcheck="false"
                    type="search" class="search-input">
            </div>
            <span class="popup-btn-close">
                <i class="fa fa-times-circle"></i>
            </span>
        </div>
        <div id="search-result">
            <div id="no-result">
                <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
            </div>
        </div>
    </div>
</div>
    
  </div>
</header>

    <div id="article-banner">
  <h2>面试官:你真的了解Java对象吗</h2>
  <p class="post-date">2020-06-29</p>
  <div class="arrow-down">
    <a href="javascript:;"></a>
  </div>
</div>
<main class="app-body flex-box">
  <!-- Article START -->
  <article class="post-article">
    <section class="markdown-content"><p>公司最近在招一位4年以上的Java高级开发工程师，今天早上HR给了我一份的简历，让我去会议室进行技术面试。</p>
<p>我大概看了下简历的基本项(男、29岁、本科、5年Java开发经验)，就去会议室面见应聘者了。</p>
<p>首先见了应聘者打了声招呼，紧接着他开始自我介绍，balabala………</p>
<p>介绍完毕后，试想着，5年工作经验应该在可以受得了我无情的毒打。</p>
<p>然后，我问了一些基础性东西，他的回答令我比较满意，但是都是凤毛麟角。</p>
<p>因为我个人喜欢深度挖掘知识点，随后，我为他准备了面试连环炮，但结果却事与愿违。</p>
<p>面了几下后了解到他的离职原因: 由于今年疫情扩散和资本市场萎缩的原因，上一家公司(国企)大幅度降薪，工作不好找。</p>
<p>不过，他还是算比较乐观的，说是同事和他同样工作经验，都可以找20k以上的薪资，他相信他也可以。</p>
<p>我面了几下后，就让回去等通知了。不是我个人比较自满，而是现在的市场太混乱、人心太浮躁罢了。</p>
<p>5年经验的技术开发者，上来只想着谈分布式、谈架构，真的是让我大为所叹。</p>
<p>不积跬步，<em>无以至千里</em>；不积小流，无以成江海。</p>
<p>架构都是一点一点的基础累积下来的，基础不扎实，谈何架构，谈何未来？</p>
<p>现在早已不是2015年那个时候，闭着眼睛会CRUD就可以找到一份待遇不错的工作。</p>
<p>我现在终于明白为什么大厂特别注重数据结构与算法、计算机基础与原理、框架原理、网络通信原理。</p>
<p>随着时代的进步，初级工程师已经太饱和了，高级工程师还很稀缺。这个社会早对IT从业人员有了更高的要求。</p>
<p>下面是我问他Java对象相关知识点的面试连环炮，希望以后的日子里，自己能够引以为戒，持续深入学习。</p>
<h1 id="1-你了解Java的Object类吗？"><a href="#1-你了解Java的Object类吗？" class="headerlink" title="1. 你了解Java的Object类吗？"></a>1. 你了解Java的Object类吗？</h1><p>万物皆对象。Java中java.lang.Object类是Java Class的超类，任何Java类的顶层都隐式继承它。</p>
<p>下面我们通过源码来学习一下Object.class:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> java.lang;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Class Object是类Object结构的根。</span></span><br><span class="line"><span class="comment"> * 每个CLass都将Object作为超类。</span></span><br><span class="line"><span class="comment"> × 所有对象（包括数组）都实现了这个类的方法。</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>  unascribed</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span>     java.lang.Class</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span>   JDK1.0</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Object</span> &#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title function_">registerNatives</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">        <span class="comment">// 静态初始化native方法，即使与操作系统绑定的C/C++方法</span></span><br><span class="line">        registerNatives();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 返回此Object的运行时类。 </span></span><br><span class="line"><span class="comment">     * 返回的类对象是被表示类的static synchronized方法锁定的对象。</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * 实际结果的类型是Class&lt;? extends |X|&gt;其中|X|是静态类型上其表达的擦除getClass被调用。</span></span><br><span class="line"><span class="comment">     * 例如，在此代码片段中不需要转换：</span></span><br><span class="line"><span class="comment">     * Number n = 0; </span></span><br><span class="line"><span class="comment">     * Class&lt;? extends Number&gt; c = n.getClass();</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span>  返回类对象的运行时类的Class对象。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@jls</span> 15.8.2 Class Literals</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">native</span> Class&lt;?&gt; getClass();</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 返回对象的哈希码值</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">native</span> <span class="type">int</span> <span class="title function_">hashCode</span><span class="params">()</span>;</span><br><span class="line">    </span><br><span class="line">     </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 返回当前对象this和obj是否指向的是同一个引用</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">equals</span><span class="params">(Object obj)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> (<span class="built_in">this</span> == obj);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 创建并返回此对象的副本。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">native</span> Object <span class="title function_">clone</span><span class="params">()</span> <span class="keyword">throws</span> CloneNotSupportedException;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 返回对象的字符串表示形式。默认：Class Name + @ + HashCode的十六进制</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">toString</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> getClass().getName() + <span class="string">&quot;@&quot;</span> + Integer.toHexString(hashCode());</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 唤醒正在等待对象监视器的单个线程。只能唤醒一个线程。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title function_">notify</span><span class="params">()</span>;</span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 唤醒正在等待对象监视器的所有线程。可以唤醒多个线程。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title function_">notifyAll</span><span class="params">()</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 使当前线程等待。</span></span><br><span class="line"><span class="comment">     * 直到另一个线程调用此对象的notify()方法或notifyAll()方法，或指定的时间timeout已到才被唤醒。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title function_">wait</span><span class="params">(<span class="type">long</span> timeout)</span> <span class="keyword">throws</span> InterruptedException;</span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 和wait(long timeout)类似，但它允许对放弃之前等待通知的时间进行更精细(纳秒)的控制。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title function_">wait</span><span class="params">(<span class="type">long</span> timeout, <span class="type">int</span> nanos)</span> <span class="keyword">throws</span> InterruptedException &#123;</span><br><span class="line">        <span class="keyword">if</span> (timeout &lt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">&quot;timeout value is negative&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (nanos &lt; <span class="number">0</span> || nanos &gt; <span class="number">999999</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(</span><br><span class="line">                <span class="string">&quot;nanosecond timeout value out of range&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (nanos &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            timeout++;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        wait(timeout);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 相当于wait(0)，线程的虚假唤醒：不可以用if判断，而是用while判断。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title function_">wait</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException &#123;</span><br><span class="line">        wait(<span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 当垃圾收集确定不再有对该对象的引用时，会调用这个方法进行GC。只会调用一次。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">finalize</span><span class="params">()</span> <span class="keyword">throws</span> Throwable &#123; &#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h1 id="2-解释一下对象的创建过程？"><a href="#2-解释一下对象的创建过程？" class="headerlink" title="2. 解释一下对象的创建过程？"></a>2. 解释一下对象的创建过程？</h1><p>当然不是简单的new Object();操作，对象的创建存在半初始化状态。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ObjectTest</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span> age ;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ObjectTest</span><span class="params">(<span class="type">int</span> age)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.age = age;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">ObjectTest</span> <span class="variable">obj</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectTest</span>(<span class="number">25</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">litong@LT:/media/litong/文档/code/java/back_end_services/java/src$ javac ObjectTest.java <span class="comment"># 编译字节码</span></span><br><span class="line">litong@LT:/media/litong/文档/code/java/back_end_services/java/src$ javap -c ObjectTest.class <span class="comment"># 查看字节码</span></span><br><span class="line">Compiled from <span class="string">&quot;ObjectTest.java&quot;</span></span><br><span class="line">public class ObjectTest &#123;</span><br><span class="line">  public ObjectTest(int);</span><br><span class="line">    Code:</span><br><span class="line">       0: aload_0</span><br><span class="line">       1: invokespecial <span class="comment">#1                  // Method java/lang/Object.&quot;&lt;init&gt;&quot;:()V</span></span><br><span class="line">       4: aload_0</span><br><span class="line">       5: iload_1</span><br><span class="line">       6: putfield      <span class="comment">#2                  // Field age:I</span></span><br><span class="line">       9: <span class="built_in">return</span></span><br><span class="line"></span><br><span class="line">  public static void main(java.lang.String[]);</span><br><span class="line">    Code:</span><br><span class="line">       0: new           <span class="comment">#3                  // class ObjectTest</span></span><br><span class="line">       3: dup</span><br><span class="line">       4: bipush        25</span><br><span class="line">       6: invokespecial <span class="comment">#4                  // Method &quot;&lt;init&gt;&quot;:(I)V</span></span><br><span class="line">       9: astore_1</span><br><span class="line">      10: <span class="built_in">return</span></span><br><span class="line">&#125; </span><br></pre></td></tr></table></figure>

<p>一个对象的创建至少经过<strong>new、dup、invokespecial、astore_1</strong>三个字节码指令:</p>
<ul>
<li>new: 当调用new指令时，JVM虚拟机向操作系统申请合适的空间，创建了一个类的实例，但是还没有调用构造器函数。</li>
<li>dup：使用<code>invokespecial命令会从</code>操作数堆栈中弹出nargs参数值和objectref<code>，</code>正是因为需要调用这个函数才导致中间必须要有一个 dup 指令，不然调用完<code>&lt;init&gt;</code>函数以后，操作数栈为空，就再也找不回刚刚创建的对象了。</li>
<li>invokespecial : 使用 <code>invokespecial</code>调用了 <code>&lt;init&gt;</code> 后才真正调用了构造器函数。</li>
<li>astore_1：将对象空间和对象引用关联。</li>
</ul>
<p>上述Java代码片段ObjectTest obj = new ObjectTest(25); 对象的转述流程如下：</p>
<ul>
<li>类校验成功后，加载ObjectTest.class。</li>
<li>内存中申请一块合适大小的内存。并在内存生成一个引用变量，此时内存地址和引用变量未产生关联。</li>
<li>第一次初始化:加载初始化，成员变量若为基本数据类型，则默认值是基本数据类型的默认值；若为引用类型，默认值为null。此时age的值为0。</li>
<li>第二次初始化:构造初始化，此时age的值为25；</li>
<li>所有初始化完成后，将引用变量的指向new的那块内存地址，完成对象的创建。</li>
</ul>
<h1 id="3-DCL单例到底需不需要加volatite？"><a href="#3-DCL单例到底需不需要加volatite？" class="headerlink" title="3. DCL单例到底需不需要加volatite？"></a>3. DCL单例到底需不需要加volatite？</h1><p>答案是加，而且一定要加。首先我们先回顾一次懒汉式单例到DCL单例的演变，然后我们一一剖析为什么一定要加volatite。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@projectName</span>: Singleton</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@className</span>: com.java.Singleton</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span>: 单例对象演示</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>: tong.li</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@createTime</span>: 2020/6/29 下午21:37</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span>: v1.0</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Singleton</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/** 单例实例引用 */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="type">Singleton</span> <span class="variable">SINGLETON</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 私有构造，禁止外部构造</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="title function_">Singleton</span><span class="params">()</span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Singleton <span class="title function_">getInstance</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">// 首先判断是否为null</span></span><br><span class="line">        <span class="keyword">if</span> (SINGLETON == <span class="literal">null</span>) &#123;   <span class="comment">// 假设所有线程都进来,先阻塞1秒，都全部唤醒后，会new多次</span></span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="comment">// 这里睡眠1秒，会实例化多次</span></span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 若为null，直接new</span></span><br><span class="line">            SINGLETON = <span class="keyword">new</span> <span class="title class_">Singleton</span>();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 返回最终的实例对象</span></span><br><span class="line">        <span class="keyword">return</span> SINGLETON;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 创建具有5个线程的线程池</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; <span class="number">5</span> ; i++) &#123;</span><br><span class="line">            <span class="comment">// 多线程访问对象，看是否同一个对象</span></span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">Thread</span>(() -&gt; System.out.println(Singleton.getInstance())).start();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 上述代码运行结果，很明显不是同一个对象，意味着该对象不是单例的</span></span><br><span class="line">com.java.object.Singleton@6fcaf925</span><br><span class="line">com.java.object.Singleton@39531411</span><br><span class="line">com.java.object.Singleton@220af032</span><br><span class="line">com.java.object.Singleton@39531411</span><br><span class="line">com.java.object.Singleton@78541db1</span><br><span class="line"><span class="comment"># 在getInstance()方法直接加synchronized运行可以解决该问题，但是锁粒度太大，性能很低效</span></span><br><span class="line">com.java.object.Singleton@4e38bc80</span><br><span class="line">com.java.object.Singleton@4e38bc80</span><br><span class="line">com.java.object.Singleton@4e38bc80</span><br><span class="line">com.java.object.Singleton@4e38bc80</span><br><span class="line">com.java.object.Singleton@4e38bc80</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 锁细化后仍然存在线程安全问题</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span>  <span class="keyword">static</span> Singleton <span class="title function_">getInstance</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="comment">// 首先判断是否为null</span></span><br><span class="line">    <span class="keyword">if</span> (SINGLETON == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="comment">// 锁粒度细小化，但是仍然存在线程安全</span></span><br><span class="line">        <span class="comment">// 如果线程1先进来再阻塞，其他线程都会进入到这个判断里等待线程1释放锁。</span></span><br><span class="line">        <span class="comment">// 若线程1创建完对象后释放锁，其他线程都可以竞争这把锁，从而会多次new</span></span><br><span class="line">        <span class="keyword">synchronized</span> (Singleton.class) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="comment">// 这里睡眠1秒，会实例化多次</span></span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 若为null，直接new</span></span><br><span class="line">            SINGLETON = <span class="keyword">new</span> <span class="title class_">Singleton</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 返回最终的实例对象</span></span><br><span class="line">    <span class="keyword">return</span> SINGLETON;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"># 锁细化后的执行结果仍然存在线程安全问题，不是单例对象。</span><br><span class="line">com.java.object.Singleton@17ea7521</span><br><span class="line">com.java.object.Singleton@220af032</span><br><span class="line">com.java.object.Singleton@6fcaf925</span><br><span class="line">com.java.object.Singleton@39531411</span><br><span class="line">com.java.object.Singleton@4e38bc80</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * DCL，双重判断保证单例</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span>  <span class="keyword">static</span> Singleton <span class="title function_">getInstance</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="comment">// 首先判断是否为null</span></span><br><span class="line">    <span class="keyword">if</span> (SINGLETON == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="comment">// 锁粒度细小化</span></span><br><span class="line">        <span class="keyword">synchronized</span> (Singleton.class) &#123;</span><br><span class="line">            <span class="comment">// DCL(Double Check Lock)，锁的双重判断，即使多线程进来，也确保是单例</span></span><br><span class="line">            <span class="keyword">if</span> (SINGLETON == <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="comment">// 这里睡眠1秒，会实例化多次</span></span><br><span class="line">                    TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// 若为null，直接new</span></span><br><span class="line">                SINGLETON = <span class="keyword">new</span> <span class="title class_">Singleton</span>();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 返回最终的实例对象</span></span><br><span class="line">    <span class="keyword">return</span> SINGLETON;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># DCL模式下肯定是单例</span></span><br><span class="line">com.java.object.Singleton@78541db1</span><br><span class="line">com.java.object.Singleton@78541db1</span><br><span class="line">com.java.object.Singleton@78541db1</span><br><span class="line">com.java.object.Singleton@78541db1</span><br><span class="line">com.java.object.Singleton@78541db1</span><br></pre></td></tr></table></figure>

<p>了解到了DCL，我们回过头来看问题，volatite有两种语义：保证线程可见和禁止指令重排序。</p>
<p>结合问题2，对象的创建存在半初始化状态，若没有被volatite修饰的，创建对象的指令有可能重排序。</p>
<p>若在此基础上多线程访问，访问到的Object可能是半初始化不完整的对象。所以一定DCL单例一定要加volatile。</p>
<h1 id="4-简述对象在内存中的布局"><a href="#4-简述对象在内存中的布局" class="headerlink" title="4. 简述对象在内存中的布局"></a>4. 简述对象在内存中的布局</h1><p>  在HotSpot虚拟机中，对象在内存中的布局分为三部分：对象头、实例数据、对齐填充。</p>
<pre><code>1. 对象头：包括两部分：Mark Word、类型指针、数组长度(如果是数组类型)
 1. Mark Word：存储对象自身的运行时数据（哈希码、GC年龄、锁标志、持有的锁等）。被设计成非固定数据结构，根据对象状态占用内部空间。64位虚拟机占用8个字节。
 2. Class Poniter：对象指向它的类元数据的指针。虚拟机通过这个指针确定对象是哪个类的实例。开启指针压缩（-XX:+UseCompressedOops）占4个字节，未开启压缩占8个字节。
 3. length：数组长度，对于数组对象，对象头中必须有一块数据记录数组长度，因为JVM无法从数组的元数据确定数组的大小。也占用4字节。
2. Instance Data：实例数据是对象真正存储的有效信息，就是代码中定义的各种类型的字段内容，包括从父类继承下来的和子类中定义的。
3. Padding： HotSpot虚拟机的自动内存管理系统要求对象起始地址必须是8字节的整数倍。当对象的实例数据部分没有对齐，用对齐填充补全，连续空间会将读效率会更高。所以对齐填充不是必然存在的。
</code></pre>
<h1 id="5-对象头具体包括什么？"><a href="#5-对象头具体包括什么？" class="headerlink" title="5. 对象头具体包括什么？"></a>5. 对象头具体包括什么？</h1><p>对象头包含Mark Word和Class Poniter。</p>
<p>在OpenJDK的HotSpot源码<a target="_blank" rel="noopener" href="http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/share/vm/oops/markOop.hpp">markOop.hpp</a> 中可以找到定义：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">ifndef</span> SHARE_VM_OOPS_MARKOOP_HPP</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> SHARE_VM_OOPS_MARKOOP_HPP</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;oops/oop.hpp&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// The markOop describes the header of an object.</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// Note that the mark is not a real oop but just a word.</span></span><br><span class="line"><span class="comment">// It is placed in the oop hierarchy for historical reasons.</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// Bit-format of an object header (most significant first, big endian layout below):</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">//  32 bits:</span></span><br><span class="line"><span class="comment">//  --------</span></span><br><span class="line"><span class="comment">//             hash:25 ------------&gt;| age:4    biased_lock:1 lock:2 (normal object)</span></span><br><span class="line"><span class="comment">//             JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)</span></span><br><span class="line"><span class="comment">//             size:32 ------------------------------------------&gt;| (CMS free block)</span></span><br><span class="line"><span class="comment">//             PromotedObject*:29 ----------&gt;| promo_bits:3 -----&gt;| (CMS promoted object)</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">//  64 bits:</span></span><br><span class="line"><span class="comment">//  --------</span></span><br><span class="line"><span class="comment">//  unused:25 hash:31 --&gt;| unused:1   age:4    biased_lock:1 lock:2 (normal object)</span></span><br><span class="line"><span class="comment">//  JavaThread*:54 epoch:2 unused:1   age:4    biased_lock:1 lock:2 (biased object)</span></span><br><span class="line"><span class="comment">//  PromotedObject*:61 ---------------------&gt;| promo_bits:3 -----&gt;| (CMS promoted object)</span></span><br><span class="line"><span class="comment">//  size:64 -----------------------------------------------------&gt;| (CMS free block)</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">//  unused:25 hash:31 --&gt;| cms_free:1 age:4    biased_lock:1 lock:2 (COOPs &amp;&amp; normal object)</span></span><br><span class="line"><span class="comment">//  JavaThread*:54 epoch:2 cms_free:1 age:4    biased_lock:1 lock:2 (COOPs &amp;&amp; biased object)</span></span><br><span class="line"><span class="comment">//  narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 -----&gt;| (COOPs &amp;&amp; CMS promoted object)</span></span><br><span class="line"><span class="comment">//  unused:21 size:35 --&gt;| cms_free:1 unused:7 ------------------&gt;| (COOPs &amp;&amp; CMS free block)</span></span><br><span class="line"><span class="comment">//</span></span><br></pre></td></tr></table></figure>

<h1 id="6-为什么堆内存到32G后，指针压缩会失效？"><a href="#6-为什么堆内存到32G后，指针压缩会失效？" class="headerlink" title="6. 为什么堆内存到32G后，指针压缩会失效？"></a>6. 为什么堆内存到32G后，指针压缩会失效？</h1><p>对象头中的Class Pointer默认占8个字节，开启-XX:+UseCompressedOops后，为了节省空间压缩为4个字节，4*8=32位表示可寻址4G个对象，在内存空间小于32G时，可以通过编码、解码方式进行优化，使得jvm可以支持更大的内存配置。当堆内存大于32G时，压缩指针参数会失效，会强制使用64位(即8字节)来对java对象寻址。</p>
<p>32位操作系统可以寻址到多大内存 答：4g 因为 2^32=4 * 1024 * 1024=4g，那么64位寻址就更大了。</p>
<p>用64位寻址，会给我们寻址带宽和对象引用造成负担。寄存器的寻址能力在32G左右，所以开启指针压缩和未开启指针压缩都会按64位进行寻址。</p>
<p>一旦你越过那个神奇的30-32G的边界，指针就会切回普通对象的指针，每个对象的指针都变长了，就会使用更多的CPU内存带宽，也就是说你实际上失去了更多的内存。事实上当内存到达40-50GB的时候，有效内存才相当于使用内存对象指针压缩技术时候的32G内存。</p>
<p>这段描述的意思就是说：即便你有足够的内存，也尽量不要超过32G，因为它浪费了内存，降低了CPU的性能，还要让GC应对大内存显得费时费力。</p>
<h1 id="7-简述对象的分配过程"><a href="#7-简述对象的分配过程" class="headerlink" title="7. 简述对象的分配过程"></a>7. 简述对象的分配过程</h1><p>优先栈上分配，分析是否有对象逃逸。栈上分配对象，对象弹栈，对象生命周期结束，不需要GC介入，效率高。</p>
<p>优先分配大对象，直接分配到老年代。</p>
<p>优先给TLAB(Thread Local Allocation Buffer，线程本地分配缓存区)分配，因为多个线程都会同一块区域分配(抢内存，俗称指针碰撞)，TLAB其实是Eden区划分好的线程区域。</p>
<p>再TLAB分配完成后，经历过一次YGC，垃圾对象直接回收，若改对象不是垃圾对象，年龄不够，复制到Surivor区，循环往复。直到年龄够大，会被放入老年代中。</p>
<p><img src="https://ltyeamin.github.io/imgs/2020/07/20200731161415.png" alt="1593940781933"></p>
<h1 id="8-Object-obj-new-Object-在内存中占用多少个字节？"><a href="#8-Object-obj-new-Object-在内存中占用多少个字节？" class="headerlink" title="8. Object obj = new Object()在内存中占用多少个字节？"></a>8. Object obj = new Object()在内存中占用多少个字节？</h1><p>普通对象开启指针压缩：Mark Word(8字节)+Class Pointer(4字节)+Padding(4字节) = 16 字节</p>
<p>普通对象未开启指针压缩(含指针压缩失效)：Mark Word(8字节)+Class Pointer(8字节)+Padding(4字节) = 20 字节</p>
<p>用代码查看内存布局：</p>
<ol>
<li><p>在pom中导入java对象布局依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--  java对象布局依赖工具 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.openjdk.jol<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jol-core<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.10<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></li>
<li><p>编写代码</p>
</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.openjdk.jol.info.ClassLayout;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@projectName</span>: ObjectLayout</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@className</span>: com.java.ObjectLayoutDemo</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span>: 对象布局演示</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>: tong.li</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@createTime</span>: 2020/6/29 下午5:38</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span>: v1.0</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ObjectLayoutDemo</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="type">long</span> a;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line"></span><br><span class="line">        <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Object</span>();</span><br><span class="line">        <span class="comment">// 打印空对象的内存布局，总共16个字节</span></span><br><span class="line">        System.out.println(ClassLayout.parseInstance(obj).toPrintable());</span><br><span class="line">        System.out.println(<span class="string">&quot;--------------------------------------------------------------&quot;</span>);</span><br><span class="line">        <span class="type">ObjectLayoutDemo</span> <span class="variable">old</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectLayoutDemo</span>();</span><br><span class="line">        <span class="comment">// 打印有实例数据对象的内存布局，</span></span><br><span class="line">        <span class="comment">// 如果a是4个字节以下的数据类型，大小仍然保持16个字节，int类型(4个字节)不用填充，char类型(2个字节)，需要填充2个字节，</span></span><br><span class="line">        <span class="comment">// 如果是long:对象头12字节+8个字节=20，需要对齐(8的整数倍)=24</span></span><br><span class="line">        System.out.println(ClassLayout.parseInstance(old).toPrintable());</span><br><span class="line">        System.out.println(<span class="string">&quot;--------------------------------------------------------------&quot;</span>);</span><br><span class="line">        <span class="comment">// 打印数组(无数据)的内存布局，4+4+4+4(数组长度)=16，不需要补齐</span></span><br><span class="line">        <span class="type">int</span>[] array1 = <span class="keyword">new</span> <span class="title class_">int</span>[<span class="number">0</span>];</span><br><span class="line">        System.out.println(ClassLayout.parseInstance(array1).toPrintable());</span><br><span class="line">        System.out.println(<span class="string">&quot;--------------------------------------------------------------&quot;</span>);</span><br><span class="line">        <span class="comment">// 打印数组(有数据)的内存布局</span></span><br><span class="line">        <span class="comment">// 16 + 2 × 4 = 24,不用补齐</span></span><br><span class="line">        <span class="type">int</span>[] array2 = <span class="keyword">new</span> <span class="title class_">int</span>[<span class="number">2</span>];</span><br><span class="line">        System.out.println(ClassLayout.parseInstance(array2).toPrintable());</span><br><span class="line">        <span class="type">int</span>[] array3 = <span class="keyword">new</span> <span class="title class_">int</span>[<span class="number">3</span>];  </span><br><span class="line">        <span class="comment">// 16+3*4=28，补齐到32字节</span></span><br><span class="line">        System.out.println(ClassLayout.parseInstance(array3).toPrintable());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># WARNING: Unable to attach Serviceability Agent. You can try again with escalated privileges. Two options: a) use -Djol.tryWithSudo=true to try with sudo; b) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope</span></span><br><span class="line"><span class="comment"># 前面8个字节是Mark Word，后面一个是Class Poniter，最后一个是内存对齐</span></span><br><span class="line">java.lang.Object object internals: </span><br><span class="line"> OFFSET  SIZE   TYPE DESCRIPTION                               VALUE</span><br><span class="line">      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)</span><br><span class="line">      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)</span><br><span class="line">      8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)</span><br><span class="line">     12     4        (loss due to the next object alignment)</span><br><span class="line">Instance size: 16 bytes</span><br><span class="line">Space losses: 0 bytes internal + 4 bytes external = 4 bytes total</span><br><span class="line"></span><br><span class="line">--------------------------------------------------------------</span><br><span class="line">com.java.object.entity.ObjectLayoutDemo object internals:</span><br><span class="line"> OFFSET  SIZE   TYPE DESCRIPTION                               VALUE</span><br><span class="line">      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)</span><br><span class="line">      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)</span><br><span class="line">      8     4        (object header)                           05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)</span><br><span class="line">     12     4        (alignment/padding gap)                  </span><br><span class="line">     16     8   long ObjectLayoutDemo.a                        0</span><br><span class="line">Instance size: 24 bytes</span><br><span class="line">Space losses: 4 bytes internal + 0 bytes external = 4 bytes total</span><br><span class="line"></span><br><span class="line">--------------------------------------------------------------</span><br><span class="line">[I object internals:</span><br><span class="line"> OFFSET  SIZE   TYPE DESCRIPTION                               VALUE</span><br><span class="line">      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)</span><br><span class="line">      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)</span><br><span class="line">      8     4        (object header)                           6d 01 00 f8 (01101101 00000001 00000000 11111000) (-134217363)</span><br><span class="line">     12     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)</span><br><span class="line">     16     0    int [I.&lt;elements&gt;                             N/A</span><br><span class="line">Instance size: 16 bytes</span><br><span class="line">Space losses: 0 bytes internal + 0 bytes external = 0 bytes total</span><br><span class="line"></span><br><span class="line">--------------------------------------------------------------</span><br><span class="line">[I object internals:</span><br><span class="line"> OFFSET  SIZE   TYPE DESCRIPTION                               VALUE</span><br><span class="line">      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)</span><br><span class="line">      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)</span><br><span class="line">      8     4        (object header)                           6d 01 00 f8 (01101101 00000001 00000000 11111000) (-134217363)</span><br><span class="line">     12     4        (object header)                           02 00 00 00 (00000010 00000000 00000000 00000000) (2)</span><br><span class="line">     16     8    int [I.&lt;elements&gt;                             N/A</span><br><span class="line">Instance size: 24 bytes</span><br><span class="line">Space losses: 0 bytes internal + 0 bytes external = 0 bytes total</span><br><span class="line"></span><br><span class="line">[I object internals:</span><br><span class="line"> OFFSET  SIZE   TYPE DESCRIPTION                               VALUE</span><br><span class="line">      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)</span><br><span class="line">      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)</span><br><span class="line">      8     4        (object header)                           6d 01 00 f8 (01101101 00000001 00000000 11111000) (-134217363)</span><br><span class="line">     12     4        (object header)                           03 00 00 00 (00000011 00000000 00000000 00000000) (3)</span><br><span class="line">     16    12    int [I.&lt;elements&gt;                             N/A</span><br><span class="line">     28     4        (loss due to the next object alignment)</span><br><span class="line">Instance size: 32 bytes</span><br><span class="line">Space losses: 0 bytes internal + 4 bytes external = 4 bytes total</span><br></pre></td></tr></table></figure>



<h1 id="9-对象怎么定位？"><a href="#9-对象怎么定位？" class="headerlink" title="9. 对象怎么定位？"></a>9. 对象怎么定位？</h1><ul>
<li>间接句柄方式：方便GC，GC复制的时候不需要移动这个句柄指针。</li>
<li>直接指针方式：访问效率高，JaHotSpot虚拟机默认使用对象定位方式。</li>
</ul>
<h1 id="10-为什么HotSpot不使用C-对象来代表Java对象？"><a href="#10-为什么HotSpot不使用C-对象来代表Java对象？" class="headerlink" title="10. 为什么HotSpot不使用C++对象来代表Java对象？"></a>10. 为什么HotSpot不使用C++对象来代表Java对象？</h1><p>HotSpot虚拟机定义了OOP/Class二元模型。Java对象里面除过有个普通对象，还有一个字节码的类对象。</p>
<p>每个C++对象里面有虚函数表。若用C++对象直接代表Java对象，Java都要装载这个虚函数表，内存占用太大，所以不采用。</p>
<h1 id="11-Class对象是在堆还是在方法区？"><a href="#11-Class对象是在堆还是在方法区？" class="headerlink" title="11. Class对象是在堆还是在方法区？"></a>11. Class对象是在堆还是在方法区？</h1><p>Class对象是存放在堆区的，不是方法区。</p>
<p>Class类的元数据(方法代码、变量名、方法名、访问权限、返回值)都在方法区(元空间或永久带)，但是Class类的实例对象是在堆区的。</p>
<p>当我们加载一个类时，实际上,Method Area区有个C++对象InstanceClassOop指向堆中的类对象。</p>
</section>
    <!-- Tags START -->
    
      <div class="tags">
        <span>Tags:</span>
        
  <a href="/tags#Java" >
    <span class="tag-code">Java</span>
  </a>

      </div>
    
    <!-- Tags END -->
    <!-- NAV START -->
    
  <div class="nav-container">
    <!-- reverse left and right to put prev and next in a more logic postition -->
    
      <a class="nav-left" href="/2020/06/18/%E6%B7%B1%E5%85%A5%E5%88%86%E6%9E%90HashMap%E6%BA%90%E7%A0%81/">
        <span class="nav-arrow">← </span>
        
          深入分析HashMap源码
        
      </a>
    
    
      <a class="nav-right" href="/2020/07/22/%E3%80%90Java%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B%E5%AE%9E%E6%88%98%E3%80%91-J.U.C%E5%B9%B6%E5%8F%91%E5%8C%85%E4%B9%8BAQS/">
        
          【Java并发编程实战】-解读J.U.C并发包之AQS
        
        <span class="nav-arrow"> →</span>
      </a>
    
  </div>

    <!-- NAV END -->
    <!-- 打赏 START -->
    
      <div class="money-like">
        <div class="reward-btn">
          赏
          <span class="money-code">
            <span class="alipay-code">
              <div class="code-image"></div>
              <b>使用支付宝打赏</b>
            </span>
            <span class="wechat-code">
              <div class="code-image"></div>
              <b>使用微信打赏</b>
            </span>
          </span>
        </div>
        <p class="notice">若你觉得我的文章对你有帮助，欢迎点击上方按钮对我打赏</p>
      </div>
    
    <!-- 打赏 END -->
    <!-- 二维码 START -->
    
      <div class="qrcode">
        <canvas id="share-qrcode"></canvas>
        <p class="notice">扫描二维码，分享此文章</p>
      </div>
    
    <!-- 二维码 END -->
    
      <!-- Utterances START -->
      <div id="utterances"></div>
      <script src="https://utteranc.es/client.js"
        repo="ltyeamin/blogtalks"
        issue-term="pathname"
        theme="github-light"
        crossorigin="anonymous"
        async></script>    
      <!-- Utterances END -->
    
  </article>
  <!-- Article END -->
  <!-- Catalog START -->
  
    <aside class="catalog-container">
  <div class="toc-main">
    <strong class="toc-title">Catalog</strong>
    
      <ol class="toc-nav"><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#1-%E4%BD%A0%E4%BA%86%E8%A7%A3Java%E7%9A%84Object%E7%B1%BB%E5%90%97%EF%BC%9F"><span class="toc-nav-text">1. 你了解Java的Object类吗？</span></a></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#2-%E8%A7%A3%E9%87%8A%E4%B8%80%E4%B8%8B%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%88%9B%E5%BB%BA%E8%BF%87%E7%A8%8B%EF%BC%9F"><span class="toc-nav-text">2. 解释一下对象的创建过程？</span></a></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#3-DCL%E5%8D%95%E4%BE%8B%E5%88%B0%E5%BA%95%E9%9C%80%E4%B8%8D%E9%9C%80%E8%A6%81%E5%8A%A0volatite%EF%BC%9F"><span class="toc-nav-text">3. DCL单例到底需不需要加volatite？</span></a></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#4-%E7%AE%80%E8%BF%B0%E5%AF%B9%E8%B1%A1%E5%9C%A8%E5%86%85%E5%AD%98%E4%B8%AD%E7%9A%84%E5%B8%83%E5%B1%80"><span class="toc-nav-text">4. 简述对象在内存中的布局</span></a></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#5-%E5%AF%B9%E8%B1%A1%E5%A4%B4%E5%85%B7%E4%BD%93%E5%8C%85%E6%8B%AC%E4%BB%80%E4%B9%88%EF%BC%9F"><span class="toc-nav-text">5. 对象头具体包括什么？</span></a></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#6-%E4%B8%BA%E4%BB%80%E4%B9%88%E5%A0%86%E5%86%85%E5%AD%98%E5%88%B032G%E5%90%8E%EF%BC%8C%E6%8C%87%E9%92%88%E5%8E%8B%E7%BC%A9%E4%BC%9A%E5%A4%B1%E6%95%88%EF%BC%9F"><span class="toc-nav-text">6. 为什么堆内存到32G后，指针压缩会失效？</span></a></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#7-%E7%AE%80%E8%BF%B0%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%88%86%E9%85%8D%E8%BF%87%E7%A8%8B"><span class="toc-nav-text">7. 简述对象的分配过程</span></a></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#8-Object-obj-new-Object-%E5%9C%A8%E5%86%85%E5%AD%98%E4%B8%AD%E5%8D%A0%E7%94%A8%E5%A4%9A%E5%B0%91%E4%B8%AA%E5%AD%97%E8%8A%82%EF%BC%9F"><span class="toc-nav-text">8. Object obj &#x3D; new Object()在内存中占用多少个字节？</span></a></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#9-%E5%AF%B9%E8%B1%A1%E6%80%8E%E4%B9%88%E5%AE%9A%E4%BD%8D%EF%BC%9F"><span class="toc-nav-text">9. 对象怎么定位？</span></a></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#10-%E4%B8%BA%E4%BB%80%E4%B9%88HotSpot%E4%B8%8D%E4%BD%BF%E7%94%A8C-%E5%AF%B9%E8%B1%A1%E6%9D%A5%E4%BB%A3%E8%A1%A8Java%E5%AF%B9%E8%B1%A1%EF%BC%9F"><span class="toc-nav-text">10. 为什么HotSpot不使用C++对象来代表Java对象？</span></a></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#11-Class%E5%AF%B9%E8%B1%A1%E6%98%AF%E5%9C%A8%E5%A0%86%E8%BF%98%E6%98%AF%E5%9C%A8%E6%96%B9%E6%B3%95%E5%8C%BA%EF%BC%9F"><span class="toc-nav-text">11. Class对象是在堆还是在方法区？</span></a></li></ol>
    
  </div>
</aside>
  
  <!-- Catalog END -->
</main>

<script>
  (function () {
    var url = 'http://example.com/2020/06/29/面试官你真的了解Java对象吗/';
    var banner = ''
    if (banner !== '' && banner !== 'undefined' && banner !== 'null') {
      $('#article-banner').css({
        'background-image': 'url(' + banner + ')'
      })
    } else {
      $('#article-banner').geopattern(url)
    }
    $('.header').removeClass('fixed-header')

    // error image
    $(".markdown-content img").on('error', function() {
      $(this).attr('src', '/css/images/error_icon.png')
      $(this).css({
        'cursor': 'default'
      })
    })

    // zoom image
    $(".markdown-content img").on('click', function() {
      var src = $(this).attr('src')
      if (src !== '/css/images/error_icon.png') {
        var imageW = $(this).width()
        var imageH = $(this).height()

        var zoom = ($(window).width() * 0.95 / imageW).toFixed(2)
        zoom = zoom < 1 ? 1 : zoom
        zoom = zoom > 2 ? 2 : zoom
        var transY = (($(window).height() - imageH) / 2).toFixed(2)

        $('body').append('<div class="image-view-wrap"><div class="image-view-inner"><img src="'+ src +'" /></div></div>')
        $('.image-view-wrap').addClass('wrap-active')
        $('.image-view-wrap img').css({
          'width': `${imageW}`,
          'transform': `translate3d(0, ${transY}px, 0) scale3d(${zoom}, ${zoom}, 1)`
        })
        $('html').css('overflow', 'hidden')

        $('.image-view-wrap').on('click', function() {
          $(this).remove()
          $('html').attr('style', '')
        })
      }
    })
  })();
</script>


  <script>
    var qr = new QRious({
      element: document.getElementById('share-qrcode'),
      value: document.location.href
    });
  </script>






    <div class="scroll-top">
  <span class="arrow-icon"></span>
</div>
    <footer class="app-footer">
  <p class="copyright">
    &copy; 2024 | Proudly powered by <a href="https://hexo.io" target="_blank">Hexo</a>
    <br>
    Theme by <a target="_blank" rel="noopener" href="https://github.com/ltyeamin">tong.li</a>
  </p>
</footer>

<script>
  function async(u, c) {
    var d = document, t = 'script',
      o = d.createElement(t),
      s = d.getElementsByTagName(t)[0];
    o.src = u;
    if (c) { o.addEventListener('load', function (e) { c(null, e); }, false); }
    s.parentNode.insertBefore(o, s);
  }
</script>
<script>
  async("https://cdn.staticfile.org/fastclick/1.0.6/fastclick.min.js", function(){
    FastClick.attach(document.body);
  })
</script>

<script>
  var hasLine = 'true';
  async("https://cdn.staticfile.org/highlight.js/9.12.0/highlight.min.js", function(){
    $('figure pre').each(function(i, block) {
      var figure = $(this).parents('figure');
      if (hasLine === 'false') {
        figure.find('.gutter').hide();
      }
      hljs.configure({useBR: true});
      var lang = figure.attr('class').split(' ')[1] || 'code';
      var codeHtml = $(this).html();
      var codeTag = document.createElement('code');
      codeTag.className = lang;
      codeTag.innerHTML = codeHtml;
      $(this).attr('class', '').empty().html(codeTag);
      figure.attr('data-lang', lang.toUpperCase());
      hljs.highlightBlock(block);
    });
  })
</script>
<!-- Baidu Tongji -->



<script src='https://cdn.staticfile.org/mermaid/8.11.2/mermaid.min.js'></script>



<script src="/js/script.js"></script>


  </body>
</html>